from decimal import Decimal

from bitstring import BitArray
import subprocess
from common.third_party.ni_types import FXP
from services.attenuators.schemas.configs import AttenuatorsConfig
from common.third_party.save_config import save_config, load_config
from settings import settings

if not settings.DEBUG:
    import spidev


class Attenuators:
    __slots__ = ['config', 'is_available']

    if not settings.DEBUG:
        SPI = spidev.SpiDev()

    ADDRESSES: list = settings.ATTENUATORS_ADDRESSES
    DEVICE = settings.ATTENUATORS_DEVICE
    BUS = settings.ATTENUATORS_BUS

    def __init__(self) -> None:
        self.config: AttenuatorsConfig = load_config(
            'attenuators/attenuators_config', AttenuatorsConfig,
            AttenuatorsConfig(values=[0.0] * settings.ATTENUATORS_NUMBER)
        )
        self.att_configure(self.config)

    def att_configure(self, config: AttenuatorsConfig) -> None:
        self.config = config
        save_config('attenuators/attenuators_config', config)

        att_data = self.prepare_att_data(config)

        if not settings.DEBUG:
            bus = 1 if self.is_invalid_bus() else settings.ATTENUATORS_BUS
            self.SPI.open(bus, self.DEVICE)
            for i in att_data:
                self.SPI.writebytes(i.bytes)
            self.SPI.close()

    def prepare_att_data(self, config: AttenuatorsConfig) -> list:
        data = [round(x * 4) for x in config.values]
        reg = FXP(signed=False,
                  enableOverflowStatus=False,
                  word_length=7,
                  integer_word_length=7)

        att_data: list = []
        for i in range(settings.ATTENUATORS_NUMBER):
            packed = reg.pack_data(Decimal(data[i]), 0)
            bit_att_array = BitArray()
            bit_att_array.append(format(self.ADDRESSES[i] & 0xff, '#010b'))
            bit_att_array.append(BitArray('0b0'))
            bit_att_array.append(format(packed, '#09b'))
            bit_att_array.reverse()
            att_data.append(bit_att_array)

        return att_data

    def is_invalid_bus(self):
        return 'z035' in subprocess.getoutput('uname -a')

